import java.util.Random;


/**
 * we have a Jbutton ButtonGrid
 * It represents a grid that consists of cells.  Every Grid belongs to a Player 
 * and it  manages the deployment of Ships onto it. 
 */
public class Grid {

	private Cell[][] cells;
	private Player player;

	/**
	 * Grid constructor. It creates the cells that form the Grid. The width and
	 * height of this grid should be equal to the constant Game.GRID_SIZE. Also
	 * sets which Player owns this Grid.
	 */
	public Grid(Player player) {
		cells = new Cell[Game.GRID_SIZE][Game.GRID_SIZE];
		for (int i = 0; i < Game.GRID_SIZE; i++) {
			for (int j = 0; j < Game.GRID_SIZE; j++) {
				cells[i][j] = new Cell(player, i, j);
			}
		}
		this.player = player;
	}

	/**
	 * Works exactly like deploy, except the position and orientation of the
	 * ship are chosen randomly. The ship must always be deployed at a valid
	 * position- no overlap and can't pass the grid border.
	 */
	public void autoDeploy(Ship ship) {
		Random rand = new Random(System.currentTimeMillis());

		int topLeftX;
		int topLeftY;
		int orientation;

		do {
			topLeftX = rand.nextInt(Game.GRID_SIZE - 1);
			topLeftY = rand.nextInt(Game.GRID_SIZE - 1);
			orientation = (int) (1 + rand.nextGaussian()) % 2;
		} while (!isValidDeployment(ship, topLeftX, topLeftY, orientation));

		deploy(ship, topLeftX, topLeftY, orientation);
	}
	

	/**
	 * Automatically chooses a valid target for this grid's player's opponent to
	 * attack on this grid. "Valid target" means, the cell that is chosen should
	 * not have been attacked already. This method should not actually perform
	 * the attack, only choose the target. It should never check whether a
	 * cell is occupied in order to make its decision about what to target. It
	 * is only allowed to guess which cell might be occupied.
	 * 
	 * A few implementation details: - This method will never be called when the
	 * game has already been won. - Your code should not assume that the
	 * returned target will actually be attacked, as this has not been
	 * specified.
	 * 
	 * @return A valid cell for this grid's player's opponent to target.
	 */
	public Cell autoTargetMe() {
		Cell cell;

		Random rand = new Random(System.currentTimeMillis());
		do {
			int x = rand.nextInt(Game.GRID_SIZE);
			int y = rand.nextInt(Game.GRID_SIZE);
			cell = cells[x][y];
		} while (cell.wasAttacked());

		return cell;
	}
	
	/**
	 * Generates an array that contains all the cells that a ship would occupy
	 * if it were placed at a particular position and orientation. The resulting
	 * array must contain the cells in a particular order - it must go from the
	 * top-left cell to bottom-right cell. In addition, the array's length must
	 * always be equal to the ship's length. If part of the ship would exceed
	 * the bounds of the grid, the corresponding entries in the array should be
	 * set to null.
	 * 
	 * For example, on a 10x10 grid, an aircraft carrier placed horizontally
	 * from (l, 5) would have the following cell positions: (1, 5), (2, 5), (3,
	 * 5), (4, 5), (5, 5)
	 * 
	 * If the aircraft carrier were placed horizontally from (8, 5) instead, it
	 * would have the following cell positions: (8, 5), (9, 5), null, null, null
	 * In that example, the last three elements would be null as they are
	 * outside the bounds of the grid.
	 * 
	 * This method should not check whether the particular positioning of the
	 * ship overlaps another ship.
	 * 
	 * @param ship
	 *            The ship to be placed. Will never be null.
	 * @param topLeftX
	 *            The x-coordinate for the top-left end of the ship. Will always
	 *            be in the range 0 to Game.GRID_SIZE-1, inclusive.
	 * @param topLeftY
	 *            The y-coordinate for the top-left end of the ship. Will always
	 *            be in the range 0 to Game.GRID_SIZE-1, inclusive.
	 * @param orientation
	 *            Will always be only one of two values - Ship.HORIZONTAL or
	 *            Ship.VERTICAL.
	 * @return Returns an array of cells, as described above.
	 */
	public Cell[] coveredCells(Ship ship, int topLeftX, int topLeftY,
			int orientation) {
		Cell[] shipCells = new Cell[ship.getLength()];
		int length = ship.getLength();
		int c = 0;

		switch (orientation) {

		case Ship.HORIZONTAL:
			int maxX = Math.min(topLeftX + length, Game.GRID_SIZE);
			for (int i = topLeftX; i < maxX; i++) {
				shipCells[c++] = this.cells[i][topLeftY];
			}
			break;

		case Ship.VERTICAL:
			int maxY = Math.min(topLeftY + length, Game.GRID_SIZE);
			for (int i = topLeftY; i < maxY; i++) {
				shipCells[c++] = this.cells[topLeftX][i];
			}
			break;
		}

		return shipCells;
	}

	/**
	 * Deploys a ship onto this grid at the specified coordinates and
	 * orientation. That means that this method sets the relevant cells of this
	 * grid to be marked as occupied by the specified ship. This method will
	 * only be called if the parameters are valid according to the
	 * isValidDeployment method.
	 * 
	 * @param ship
	 *            The ship to be placed. Will never be null.
	 * @param topLeftX
	 *            The x-coordinate for the top-left end of the ship. Will always
	 *            be in the range 0 to Game.GRID_SIZE-1, inclusive.
	 * @param topLeftY
	 *            The y-coordinate for the top-left end of the ship. Will always
	 *            be in the range 0 to Game.GRID_SIZE-1, inclusive.
	 * @param orientation
	 *            Will always be only one of two values - Ship.HORIZONTAL or
	 *            Ship.VERTICAL.
	 * @return Returns true if the ship was successfully deployed, otherwise
	 *         false.
	 */
	public boolean deploy(Ship ship, int topLeftX, int topLeftY, int orientation) {
		Cell[] cells = coveredCells(ship, topLeftX, topLeftY, orientation);
		for (int i = 0; i < cells.length; i++) {
			cells[i].occupyWith(ship);
		}
		return true;
	}

	/**
	 * Returns the cell in this grid that is at the specified coordinates.
	 * 
	 * @param x
	 *            The x-coordinate of the cell. Will always be in the range 0 to
	 *            Game.GRID_SIZE-1, inclusive.
	 * @param y
	 *            The y-coordinate of the cell. Will always be in the range 0 to
	 *            Game.GRID_SIZE-1, inclusive.
	 * @return The cell at the specified coordinates.
	 */
	public Cell getCell(int x, int y) {
		return cells[x][y];
	}

	/** 
	 * @return Returns the player that owns this grid. 
	 * */
	public Player getPlayer() {
		return player;
	}

	/**
	 * Checks whether it is valid to deploy a ship at a particular position and
	 * orientation. Not allow to overlap or exceed the boundaries
	 * 
	 * @return true if valid.
	 */
	public boolean isValidDeployment(Ship ship, int topLeftX, int topLeftY,
			int orientation) {

		Cell[] coveredCells = this.coveredCells(ship, topLeftX, topLeftY,
				orientation);

		for (int i = 0; i < coveredCells.length; i++) {
			Cell cell = coveredCells[i];
			// not allow to exceed the boundaries
			if (cell == null) {
				return false;
			}
			// not allow to overlap
			Ship occupyingShip = cell.getOccupyingShip();
			if ((occupyingShip != null) && (occupyingShip != ship)) {
				return false;
			}
		}

		return true;
	}

}
